﻿
#if 0

#pragma once

#include "tools/Variant_types.h"

namespace tools
{
    struct Variant: variant_detail::VariantTypes
    {
       ~Variant();
        Variant();
        Variant(const Variant&   src);
        Variant(const char*    src);
        Variant(const wchar_t* src);
        Variant(const Record&  src);

        template<class T> Variant(const T& src); 

        Variant& operator= (const Variant& src);
        void Clear();

        template<class T> static Variant MakeMinsize(const T& v);
    public:
        operator const Record&()const;
        operator const char*()const;
        operator const wchar_t*()const;
        template<class T> operator const T&()const;
        template<class T> operator T&();
    public:
        template<class T> bool Is()const;
        template<class T> bool Can()const;

        #define ONLY_FOR_INTEGER \
            typename ::std::enable_if< variant_detail::PropertyType<T>::eIS_INT, T >::type
        #define ONLY_FOR_FLOATING \
            typename ::std::enable_if< variant_detail::PropertyType<T>::eIS_FLOAT, T >::type
        #define ONLY_FOR_STRICT \
            typename ::std::enable_if< variant_detail::PropertyType<T>::eIS_STRICT, T >::type
        #define COMPILE_ERROR_FOR_OTHER \
            typename ::std::enable_if< variant_detail::PropertyType<T>::eIS_OTHER, T >::type

        template<class T> ONLY_FOR_INTEGER        As()const;
        template<class T> ONLY_FOR_FLOATING       As()const;
        template<class T> const ONLY_FOR_STRICT&  As()const;
        template<class T> ONLY_FOR_STRICT&        As();
        template<class T> COMPILE_ERROR_FOR_OTHER As()const;
    public:
        bool operator == (const Variant& src)const;
        bool operator != (const Variant& src)const;
        bool Empty()const;
        const ::std::type_info& GetTypeInfo()const;
        eTYPE GetType()const;
    public:
        static const ::std::type_info& GetTypeInfo(const eTYPE type);
        static bool Variant::IsFloating(const eTYPE type);
        static bool Variant::IsInteger(const eTYPE type);
    public:
        template<class T>friend ::std::basic_ostream<T>& operator<<(::std::basic_ostream<T>& os, const Variant& obj )
        {
            switch (obj.mType)
            {
                case tools::variant_detail::VariantTypes::eBOOL:    os<< Cast<eBOOL>(obj.mBuf);            break;
                case tools::variant_detail::VariantTypes::eINT8:    os<< Cast<eINT8>(obj.mBuf);            break;
                case tools::variant_detail::VariantTypes::eINT16:   os<< Cast<eINT16>(obj.mBuf);           break;
                case tools::variant_detail::VariantTypes::eINT32:   os<< Cast<eINT32>(obj.mBuf);           break;
                case tools::variant_detail::VariantTypes::eINT64:   os<< Cast<eINT64>(obj.mBuf);           break;
                case tools::variant_detail::VariantTypes::eUINT8:   os<< Cast<eUINT8>(obj.mBuf);           break;
                case tools::variant_detail::VariantTypes::eUINT16:  os<< Cast<eUINT16>(obj.mBuf);          break;
                case tools::variant_detail::VariantTypes::eUINT32:  os<< Cast<eUINT32>(obj.mBuf);          break;
                case tools::variant_detail::VariantTypes::eUINT64:  os<< Cast<eUINT64>(obj.mBuf);          break;
                case tools::variant_detail::VariantTypes::eF32:     os<< Cast<eF32>(obj.mBuf);             break;
                case tools::variant_detail::VariantTypes::eF64:     os<< Cast<eF64>(obj.mBuf);             break;
                case tools::variant_detail::VariantTypes::eSTRING:  os<< Cast<eSTRING>(obj.mBuf).c_str();  break;
                case tools::variant_detail::VariantTypes::eWSTRING: os<< Cast<eWSTRING>(obj.mBuf).c_str(); break;
                case tools::variant_detail::VariantTypes::eNULL:    os<< "null";                           break;
                case tools::variant_detail::VariantTypes::eMAP:     os<< "map";                            break;
                case tools::variant_detail::VariantTypes::eVECTOR:  os<< "vec";                            break;
                case tools::variant_detail::VariantTypes::eBLOB:    os<< "blob";                           break;
                case tools::variant_detail::VariantTypes::eRECORDS: os<< "records";                        break;
                case tools::variant_detail::VariantTypes::eRECORD:  os<< "record";                         break;
                default:
                    assert(!"INVALID_TYPE_SWITCH");  
                    break;
            }
            return os;
        }
    private:
        #define ONLY_FOR_SIGNED_INTEGER \
            typename ::std::enable_if< variant_detail::PropertyType<T>::eSIGNED_INTEGER, T >::type
        #define ONLY_FOR_USIGNED_INTEGER \
            typename ::std::enable_if< variant_detail::PropertyType<T>::eUNSIGNED_INTEGER, T >::type

        template<class T> static Variant Limits(const T& v, ONLY_FOR_SIGNED_INTEGER*  = nullptr);
        template<class T> static Variant Limits(const T& v, ONLY_FOR_USIGNED_INTEGER* = nullptr);
        template<class T> static Variant Limits(const T& v, ONLY_FOR_FLOATING*        = nullptr);
        template<class T> static Variant Limits(const T& v, ONLY_FOR_STRICT*          = nullptr);
        template<class T> static Variant Limits(const T& v, COMPILE_ERROR_FOR_OTHER*  = nullptr);
    private:

        template<class T> T CastType()const;
        void ThrowIfFalse(const bool valid)const;
        size_t GetSize()const;

        #define DEDUCE typename variant_detail::Enum2Type<N>::
        template<Variant::eTYPE N> static const DEDUCE Type& Cast(const Byte* buf);
        template<Variant::eTYPE N> static DEDUCE Type& Cast(Byte* buf);
        #undef DEDUCE
    private:
        Byte  mBuf[eSIZE_BUFF];
        eTYPE mType;
    };

//---------------------------------------------------------------------------------------------
    template<class T> Variant::Variant(const T& src) 
    {
        variant_detail::Type2Enum<T>();
        mType = static_cast<eTYPE>(variant_detail::Type2Enum<T>::eTYPE);
        new(mBuf) T(src);	  
    }
//---------------------------------------------------------------------------------------------
    template<class T> Variant::operator const T&()const
    {
        variant_detail::Type2Enum<T>();
        ThrowIfFalse( Is<T>() );
        return *reinterpret_cast<const T*>(mBuf);
    }
    template<class T> Variant::operator T&() 
    {
        const T& ref = const_cast<const Variant&>(*this);
        return const_cast<T&>(ref);  
    }
//---------------------------------------------------------------------------------------------

    template<class T> bool Variant::Is()const { return mType == variant_detail::Type2Enum<T>::eTYPE; }

    template<class T> bool Variant::Can()const
    {
        typedef variant_detail::PropertyType<T> Property;

        if(Property::eIS_STRICT)
            return Is<T>();
        if(sizeof(T) < GetSize())
            return false;
        if(Property::eIS_INT)
            return IsInteger(mType);
        if(Property::eIS_FLOAT)
            return IsFloating(mType) || IsInteger(mType);
        return false;
    }

//---------------------------------------------------------------------------------------------
    template<class T> ONLY_FOR_INTEGER  Variant::As()const
    {
        ThrowIfFalse( sizeof(T)>=GetSize() && IsInteger(mType) );
        return CastType<T>();
    }
//---------------------------------------------------------------------------------------------
    template<class T> ONLY_FOR_FLOATING Variant::As()const
    {
        ThrowIfFalse( sizeof(T)>=GetSize() && (IsFloating(mType) || IsInteger(mType)) );
        return CastType<T>();
    }
//---------------------------------------------------------------------------------------------
    template<class T> ONLY_FOR_STRICT&  Variant::As()             { return *this; }
    template<class T> const ONLY_FOR_STRICT&  Variant::As()const  { return *this; }
//---------------------------------------------------------------------------------------------    
    template<class T> COMPILE_ERROR_FOR_OTHER  Variant::As()const 
    {
        static_assert( false, "THIS_TYPE_IS_NOT_SUPPORT" ); 
    }
//---------------------------------------------------------------------------------------------
    template<Variant::eTYPE N> static const typename variant_detail::Enum2Type<N>::Type& Variant::Cast(const Byte* buf)
    {
        typedef typename variant_detail::Enum2Type<N>::Type T;
        return *(reinterpret_cast<const T*>(buf));
    }
    template<Variant::eTYPE N> static typename variant_detail::Enum2Type<N>::Type& Variant::Cast(Byte* buf)
    {
        typedef typename variant_detail::Enum2Type<N>::Type T;
        return *(reinterpret_cast<T*>(buf));
    }
//---------------------------------------------------------------------------------------------
    template<class T> T Variant::CastType()const
    {
        switch (mType)
        {
            case eINT8:   return static_cast<T>(Cast<eINT8>(mBuf))   ; 
            case eINT16:  return static_cast<T>(Cast<eINT16>(mBuf))  ; 
            case eINT32:  return static_cast<T>(Cast<eINT32>(mBuf))  ; 
            case eINT64:  return static_cast<T>(Cast<eINT64>(mBuf))  ; 
            case eUINT8:  return static_cast<T>(Cast<eUINT8>(mBuf))  ; 
            case eUINT16: return static_cast<T>(Cast<eUINT16>(mBuf)) ;  
            case eUINT32: return static_cast<T>(Cast<eUINT32>(mBuf)) ; 
            case eUINT64: return static_cast<T>(Cast<eUINT64>(mBuf)) ; 
            case eF32:    return static_cast<T>(Cast<eF32>(mBuf))    ; 
            case eF64:    return static_cast<T>(Cast<eF64>(mBuf))    ; 
        }
        throw ::std::runtime_error("ERROR_INVALID_TYPE"); 
    }
//---------------------------------------------------------------------------------------------

#define RETURN_IF_GRATIFY(type)                     \
    if( ::std::numeric_limits<type>::max()>= v )    \
        return Variant( static_cast<type>(v) ) ;

    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_SIGNED_INTEGER*)
    {
        RETURN_IF_GRATIFY(I8);
        RETURN_IF_GRATIFY(I16);
        RETURN_IF_GRATIFY(I32);
        RETURN_IF_GRATIFY(I64);
        return Variant(v);
    }
    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_USIGNED_INTEGER*)
    {
        RETURN_IF_GRATIFY(U8);
        RETURN_IF_GRATIFY(U16);
        RETURN_IF_GRATIFY(U32);
        RETURN_IF_GRATIFY(U64);
        return Variant(v);
    }
    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_FLOATING*)
    {
        RETURN_IF_GRATIFY(F32);
        RETURN_IF_GRATIFY(F64);
        return Variant(v);
    }
    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_STRICT*) { return Variant(v); }
            
    template<class T> Variant Limits(const T& v, COMPILE_ERROR_FOR_OTHER*)
    {
        static_assert( false, "THIS_TYPE_IS_NOT_SUPPORT" ); 
    }

//---------------------------------------------------------------------------------------------
#undef RETURN_IF_GRATIFY
#undef ONLY_FOR_SIGNED_INTEGER 
#undef ONLY_FOR_USIGNED_INTEGER 

#undef ONLY_FOR_INTEGER
#undef ONLY_FOR_FLOATING 
#undef ONLY_FOR_STRICT 
#undef COMPILE_ERROR_FOR_OTHER 
//---------------------------------------------------------------------------------------------
    template<class T> Variant Variant::MakeMinsize(const T& v) { return Limits(v); }
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------



}//namespace tools


#endif